The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
Changes 064
MANIFEST 312
META.yml 44
Makefile.PL 1111
README 1018
benchmarks/ab.pl 22
eg/dot-psgi/image.psgi 11
lib/HTTP/Message/PSGI.pm 11
lib/HTTP/Server/PSGI.pm 10240
lib/Plack/App/URLMap.pm 015
lib/Plack/Component.pm 12
lib/Plack/Handler/Apache2.pm 1412
lib/Plack/Handler/CGI.pm 04
lib/Plack/Handler/FCGI.pm 1330
lib/Plack/Handler/HTTP/Server/PSGI.pm 206
lib/Plack/Handler/Net/FastCGI.pm 0285
lib/Plack/Loader/Delayed.pm 070
lib/Plack/Loader.pm 11
lib/Plack/Middleware/HTTPExceptions.pm 34
lib/Plack/Middleware/JSONP.pm 1715
lib/Plack/Middleware/LighttpdScriptNameFix.pm 093
lib/Plack/Middleware/Lint.pm 424
lib/Plack/Middleware/Log4perl.pm 02
lib/Plack/Middleware/StackTrace.pm 953
lib/Plack/Request.pm 88
lib/Plack/Response.pm 11
lib/Plack/Runner.pm 1134
lib/Plack/Server/ServerSimple.pm 11
lib/Plack/Server/Standalone/Prefork.pm 15
lib/Plack/Test/Suite.pm 1626
lib/Plack/Util.pm 811
lib/Plack.pm 1325
scripts/plackup 610
share/baybridge.jpg --
share/kyoto.jpg --
t/FCGIUtils.pm 210
t/Plack-Handler/fcgi.t 1220
t/Plack-Handler/net_fastcgi.t 036
t/Plack-Handler/standalone-prefork.t 150
t/Plack-Loader/auto_fallback.t 01
t/Plack-Loader/delayed.t 028
t/Plack-Middleware/component.t 062
t/Plack-Middleware/content_length.t 22
t/Plack-Middleware/jsonp.t 100
t/Plack-Middleware/log_dispatch.t 11
t/Plack-Middleware/stacktrace_force.t 039
t/Plack-Middleware/stacktrace_streaming.t 030
t/Plack-Middleware/stacktrace_utf8.t 028
t/Plack-Middleware/urlmap_ports.t 033
t/Plack-Request/upload-large.t 22
t/Plack-Runner/options.t 02
51 files changed (This is a version diff) 3251184
@@ -2,6 +2,70 @@ Revision history for Perl extension Plack
 
 Take a look at http://github.com/miyagawa/Plack/issues for the planned changes before 1.0 release.
 
+0.9933  Tue Apr 27 14:32:23 PDT 2010
+        - refactored the app.psgi loading error handling
+        - Enable type checking of the app in Lint->wrap
+        - allow plackup -e'...'
+        - Disable FCGI::Client/Net::FastCGI test by default
+
+0.9932  Mon Apr 19 15:23:55 JST 2010
+        - Enable Lint middleware by default in the development env
+        - Lint middleware now validates $app on startup
+        - Fixed documentations on middleware and handlers
+
+0.9931  Fri Apr 16 23:52:27 PDT 2010
+        - replace kyoto.jpg test image file with smaller baybridge.jpg to strip down the tarball size
+          from 2.5MB to 212KB.
+
+0.9930  Tue Apr 13 20:18:06 PDT 2010
+        - Added Plack::Handler::Net::FastCGI (chansen)
+        - Made Test::TCP a hard dependency since Plack::Test needs it
+        - Added Delayed loader for Starlet and Starman (clkao)
+        - Hide logger middleware from log4perl's caller stack (haarg)
+
+0.9929  Wed Mar 31 00:33:10 PDT 2010
+        - Middleware::JSONP: Simplified code and does not support IO response body type
+        - fcgi.t: skip tests with lighttpd < 1.4.17 per CPAN Testers #7040400
+
+0.9928  Mon Mar 29 17:02:42 PDT 2010
+        - log_dispatch.t: require Log::Dispatch::Array
+
+0.9927  Mon Mar 29 12:43:44 PDT 2010
+        - require newer Log::Dispatch (confound)
+        - StackTrace: Encode exceptions in utf-8 in case they include wide characters #95 (tokuhirom)
+        - StackTrace: Depends on a new Devel::StackTrace::AsHTML that escapes wide characters
+        - StackTrace: Display stacktrace only if the thrown exception is a direct error #91 (frodwith)
+        - StackTrace: Added 'force' option to force stacktrace in 500 errors
+        - Avoid warnings when response_cb filter returns undef in ARRAY response body #92 (hiratara)
+        - URLMap: Ignore port number if it matches with SERVER_PORT #90 (omega)
+        - URLMap: Enable debug print with PLACK_URLMAP_DEBUG=1 #94
+        - JSONP: Fixed possible infinite-loop when using with IO response body (hiratara)
+        - Fixed the compatiblity issues with FastCGI docs and tests with lighttpd 1.4.26 (tadam)
+        - LighttpdScriptNameFix: Added 'script_name' option (tadam)
+
+0.9926  Sun Mar 28 14:37:03 PDT 2010
+        - Added -v|--version option to plackup and the ability for Plack::Runner users to override
+
+0.9925  Sat Mar 27 19:03:57 PDT 2010
+        - Make this a non-devel release
+
+0.99_24 Sat Mar 27 13:31:51 PDT 2010
+        - Disable Devel::StackTrace::WithLexicals for now until PadWalker RT #55242 is fixed
+
+0.99_23 Sat Mar 27 01:02:24 PDT 2010
+        - Dropped keep-alive code from HTTP::Server::PSGI now that Starlet clones the code
+        - Special case --disable-* and --enable-* command line options in plackup and Plack::Runner
+
+0.99_22 Thu Mar 25 19:48:08 PDT 2010
+        - INCOMPATIBLE: removed --max-workers option from the default standalone server.
+          Now it gives you warnings and falls back to the single process mode.
+
+0.99_21 Thu Mar 25 15:05:53 PDT 2010
+        - INCOMPATIBLE: removed a workaround for lighttpd SCRIPT_NAME bug in FCGI handler
+          See http://github.com/miyagawa/Plack/issues#issue/68 for details.
+        - HTTPException now logs standard exceptions to psgi.errors
+        - micro optimization for Plack::Request content() method
+
 0.9920  Thu Mar 18 23:48:06 PDT 2010
         - Fixed URL path prefix matching in URLMap (hiratara)
         - Fixed Plack::Request->content on GET with FastCGI servers (sunnavy)
@@ -65,10 +65,12 @@ lib/Plack/Handler/CGI.pm
 lib/Plack/Handler/FCGI.pm
 lib/Plack/Handler/HTTP/Server/PSGI.pm
 lib/Plack/Handler/HTTP/Server/Simple.pm
+lib/Plack/Handler/Net/FastCGI.pm
 lib/Plack/Handler/Standalone.pm
 lib/Plack/HTTPParser.pm
 lib/Plack/HTTPParser/PP.pm
 lib/Plack/Loader.pm
+lib/Plack/Loader/Delayed.pm
 lib/Plack/Loader/Restarter.pm
 lib/Plack/Loader/Shotgun.pm
 lib/Plack/Middleware.pm
@@ -85,6 +87,7 @@ lib/Plack/Middleware/ErrorDocument.pm
 lib/Plack/Middleware/Head.pm
 lib/Plack/Middleware/HTTPExceptions.pm
 lib/Plack/Middleware/JSONP.pm
+lib/Plack/Middleware/LighttpdScriptNameFix.pm
 lib/Plack/Middleware/Lint.pm
 lib/Plack/Middleware/Log4perl.pm
 lib/Plack/Middleware/LogDispatch.pm
@@ -126,12 +129,12 @@ lib/Plack/Test/Suite.pm
 lib/Plack/Util.pm
 lib/Plack/Util/Accessor.pm
 Makefile.PL
-MANIFEST
+MANIFEST			This list of files
 META.yml
 README
 scripts/plackup
+share/baybridge.jpg
 share/face.jpg
-share/kyoto.jpg
 t/00_compile.t
 t/FCGIUtils.pm
 t/HTTP-Message-PSGI/utf8_req.t
@@ -143,11 +146,12 @@ t/Plack-Handler/cgi.t
 t/Plack-Handler/fcgi.t
 t/Plack-Handler/fcgi_client.t
 t/Plack-Handler/http_server_simple.t
-t/Plack-Handler/standalone-prefork.t
+t/Plack-Handler/net_fastcgi.t
 t/Plack-Handler/standalone.t
 t/Plack-HTTPParser-PP/simple.t
 t/Plack-Loader/auto.t
 t/Plack-Loader/auto_fallback.t
+t/Plack-Loader/delayed.t
 t/Plack-Loader/shotgun.t
 t/Plack-Middleware/access_log.t
 t/Plack-Middleware/access_log_timed.t
@@ -162,6 +166,7 @@ t/Plack-Middleware/cgi-bin/hello3.cgi
 t/Plack-Middleware/cgibin.t
 t/Plack-Middleware/chunked.t
 t/Plack-Middleware/component-leak.t
+t/Plack-Middleware/component.t
 t/Plack-Middleware/conditional.t
 t/Plack-Middleware/conditionalget.t
 t/Plack-Middleware/content_length.t
@@ -190,12 +195,16 @@ t/Plack-Middleware/runtime.t
 t/Plack-Middleware/simple_content_filter.t
 t/Plack-Middleware/simple_logger.t
 t/Plack-Middleware/stacktrace.t
+t/Plack-Middleware/stacktrace_force.t
+t/Plack-Middleware/stacktrace_streaming.t
+t/Plack-Middleware/stacktrace_utf8.t
 t/Plack-Middleware/static.t
 t/Plack-Middleware/static.txt
 t/Plack-Middleware/static_env.t
 t/Plack-Middleware/urlmap.t
 t/Plack-Middleware/urlmap_builder.t
 t/Plack-Middleware/urlmap_env.t
+t/Plack-Middleware/urlmap_ports.t
 t/Plack-Middleware/wrapcgi.t
 t/Plack-Middleware/xframework.t
 t/Plack-Middleware/xsendfile.t
@@ -1,12 +1,11 @@
 ---
 abstract: 'Perl Superglue for Web frameworks and Web Servers (PSGI toolkit)'
 author:
-  - '- Tatsuhiko Miyagawa'
+  - 'Tatsuhiko Miyagawa'
 build_requires:
   ExtUtils::MakeMaker: 6.42
   Test::More: 0.88
   Test::Requires: 0
-  Test::TCP: 0.11
 configure_requires:
   ExtUtils::MakeMaker: 6.42
 distribution_type: module
@@ -24,13 +23,14 @@ no_index:
     - xt
 requires:
   Devel::StackTrace: 0
-  Devel::StackTrace::AsHTML: 0
+  Devel::StackTrace::AsHTML: 0.09
   File::ShareDir: 1.00
   Filesys::Notify::Simple: 0
   HTTP::Body: 1.06
   Hash::MultiValue: 0.05
   LWP: 5.814
   Pod::Usage: 0
+  Test::TCP: 0.11
   Try::Tiny: 0
   URI: 1.36
   parent: 0
@@ -38,4 +38,4 @@ requires:
 resources:
   license: http://dev.perl.org/licenses/
   repository: git://github.com/miyagawa/Plack.git
-version: 0.9920
+version: 0.9933
@@ -9,26 +9,26 @@ name 'Plack';
 all_from 'lib/Plack.pm';
 readme_from 'lib/Plack.pm';
 
-requires 'LWP', 5.814; # HTTP::Status, HTTP::Headers and HTTP::Request
-requires 'URI', 1.36;
-requires 'Pod::Usage';  # plackup
-requires 'File::ShareDir', '1.00'; # Plack::Test::Suite
+requires 'LWP', 5.814;                      # HTTP::Status, HTTP::Headers and HTTP::Request
+requires 'URI', 1.36;                       # URI::Escape
+requires 'Pod::Usage';                      # plackup
+requires 'File::ShareDir', '1.00';          # Plack::Test::Suite
 requires 'Try::Tiny';
 requires 'parent';
 
-requires 'Devel::StackTrace'; # Middleware::StackTrace
-requires 'Devel::StackTrace::AsHTML'; # Middleware::StackTrace
+requires 'Devel::StackTrace';               # Middleware::StackTrace
+requires 'Devel::StackTrace::AsHTML', 0.09; # Middleware::StackTrace
 
-requires 'Filesys::Notify::Simple'; # plackup -r
+requires 'Filesys::Notify::Simple';         # plackup -r
 
-requires 'Hash::MultiValue', 0.05; # Plack::Request
-requires 'HTTP::Body', 1.06; # Plack::Request
+requires 'Hash::MultiValue', 0.05;          # Plack::Request
+requires 'HTTP::Body', 1.06;                # Plack::Request
+requires 'Test::TCP', 0.11;                 # Plack::Test needs to be installed
 
 build_requires 'Test::More', 0.88;
-build_requires 'Test::TCP', 0.11;
 test_requires 'Test::Requires';
 
-tests 't/*.t t/*/*.t t/*/*/*.t t/*/*/*/*.t t/*/*/*/*/*.t';
+tests 't/*.t t/*/*.t';
 author_tests 'xt';
 
 install_share 'share';
@@ -12,14 +12,17 @@ DESCRIPTION
 MODULES AND UTILITIES
   Plack::Handler
     Plack::Handler and its subclasses contains adapters for web servers. We
-    have adapters for Standalone, CGI, FCGI, Apache, AnyEvent, Coro,
-    Danga::Socket and many server environments that you can run PSGI
-    applications on.
+    have adapters for the built-in standalone web server HTTP::Server::PSGI,
+    CGI, FCGI, Apache1, Apache2, Net::FastCGI and HTTP::Server::Simple
+    included in the core Plack distribution.
+
+    There are also many HTTP server implementations on CPAN that has Plack
+    handlers.
 
     See Plack::Handler how to write your own adapters.
 
   Plack::Loader
-    Plack::Loader is a loader to load one of Plack::Server adapters and run
+    Plack::Loader is a loader to load one of Plack::Handler adapters and run
     PSGI application code reference with it.
 
   Plack::Util
@@ -90,8 +93,13 @@ MODULES AND UTILITIES
 CONTRIBUTING
   Patches and Bug Fixes
     Small patches and bug fixes can be either submitted via nopaste on IRC
-    <irc://irc.perl.org/#plack> or email. You could also fork on github
-    (http://github.com/miyagawa/Plack) to make larger fixes.
+    <irc://irc.perl.org/#plack> or the github issue tracker
+    <http://github.com/miyagawa/Plack/issues>. Forking on github
+    <http://github.com/miyagawa/Plack> is another good way if you intend to
+    make larger fixes.
+
+    See also <http://contributing.appspot.com/plack> when you think this
+    document is terribly outdated.
 
   Module Namespaces
     Modules added to the Plack:: sub-namespaces should be reasonably generic
@@ -117,12 +125,12 @@ CONTRIBUTING
     it's supposed to run on CGI and that is a really bad choice and confuse
     people.
 
-COPYRIGHT
-    Copyright 2009- Tatsuhiko Miyagawa
-
 AUTHOR
     Tatsuhiko Miyagawa
 
+COPYRIGHT
+    Copyright 2009-2010 Tatsuhiko Miyagawa
+
 CONTRIBUTORS
     Yuval Kogman (nothingmuch)
 
@@ -130,7 +138,7 @@ CONTRIBUTORS
 
     Kazuhiro Osawa (Yappo)
 
-    Kzzuho Oku
+    Kazuho Oku
 
     Florian Ragwitz (rafl)
 
@@ -17,12 +17,12 @@ my $url = 'http://127.0.0.1/';
 my @try = (
     [ 'AnyEvent::HTTPD' ],
     [ 'HTTP::Server::PSGI' ],
-    [ 'HTTP::Server::PSGI', ' (workers=10)', max_workers => 10 ],
     [ 'Twiggy' ],
     [ 'HTTP::Server::Simple' ],
     [ 'Corona' ],
     [ 'Danga::Socket' ],
-    [ 'POE' ],
+    [ '+POE::Component::Server::PSGI' ],
+    [ 'Starlet', ' (workers=10)', max_workers => 10 ],
     [ 'Starman', ' (workers=10)', workers => 10 ],
 );
 
@@ -1,5 +1,5 @@
 use File::Basename;
-my $path = $ENV{PSGI_IMAGE_FILE} || dirname(__FILE__) . "/../../share/kyoto.jpg";
+my $path = $ENV{PSGI_IMAGE_FILE} || dirname(__FILE__) . "/../../share/baybridge.jpg";
 my $handler = sub {
     open my $fh, "<:raw", $path or die $!;
     return [ 200, [ "Content-Type" => "image/jpeg", "X-Sendfile" => $path, "Content-Length" => -s $fh ], $fh ];
@@ -113,7 +113,7 @@ sub _res_from_psgi {
         $res->headers->header(@$headers) if @$headers;
 
         if (ref $body eq 'ARRAY') {
-            $res->content(join '', @$body);
+            $res->content(join '', grep defined, @$body);
         } else {
             local $/ = \4096;
             my $content;
@@ -2,6 +2,7 @@ package HTTP::Server::PSGI;
 use strict;
 use warnings;
 
+use Carp ();
 use Plack;
 use Plack::HTTPParser qw( parse_http_request );
 use IO::Socket::INET;
@@ -37,27 +38,16 @@ sub new {
         host               => $args{host} || 0,
         port               => $args{port} || 8080,
         timeout            => $args{timeout} || 300,
-        keepalive_timeout  => $args{keepalive_timeout} || 2,
-        max_keepalive_reqs => $args{max_keepalive_reqs},
         server_software    => $args{server_software} || $class,
         server_ready       => $args{server_ready} || sub {},
-        max_workers        => $args{max_workers} || 1,
         max_reqs_per_child => $args{max_reqs_per_child} || 100,
     }, $class;
 
-    if ($self->{max_workers} > 1) {
-        try {
-            require Parallel::Prefork;
-            $self->{prefork} = 1;
-            $self->{max_keepalive_reqs} ||= 100;
-            $self->{server_software} .= " (prefork)";
-        } catch {
-            die "You need to install Parallel::Prefork to run multi workers (max_workers=$self->{max_workers}): $_";
-        };
-    }
-
-    unless ($self->{prefork}) {
-        $self->{max_keepalive_reqs} ||= 1;
+    if ($args{max_workers} && $args{max_workers} > 1) {
+        Carp::carp(
+            "Preforking in $class is deprecated. Falling back to the non-forking mode. ",
+            "If you need preforking, use Starman or Starlet instead and run like `plackup -s Starlet`",
+        );
     }
 
     $self;
@@ -66,12 +56,7 @@ sub new {
 sub run {
     my($self, $app) = @_;
     $self->setup_listener();
-
-    if ($self->{prefork}) {
-        $self->run_prefork($app);
-    } else {
-        $self->accept_loop($app);
-    }
+    $self->accept_loop($app);
 }
 
 sub setup_listener {
@@ -87,24 +72,6 @@ sub setup_listener {
     $self->{server_ready}->($self);
 }
 
-sub run_prefork {
-    my($self, $app) = @_;
-
-    my $pm = Parallel::Prefork->new({
-        max_workers => $self->{max_workers},
-        trap_signals => {
-            TERM => 'TERM',
-            HUP  => 'TERM',
-        },
-    });
-    while ($pm->signal_received ne 'TERM') {
-        $pm->start and next;
-        $self->accept_loop($app, $self->{max_reqs_per_child});
-        $pm->finish;
-    }
-    $pm->wait_all_children;
-}
-
 sub accept_loop {
     # TODO handle $max_reqs_per_child
     my($self, $app, $max_reqs_per_child) = @_;
@@ -117,43 +84,32 @@ sub accept_loop {
         if (my $conn = $self->{listen_sock}->accept) {
             $conn->setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
                 or die "setsockopt(TCP_NODELAY) failed:$!";
-            my $req_count = 0;
-            while (1) {
-                ++$req_count;
-                ++$proc_req_count;
-                my $env = {
-                    SERVER_PORT => $self->{port},
-                    SERVER_NAME => $self->{host},
-                    SCRIPT_NAME => '',
-                    REMOTE_ADDR => $conn->peerhost,
-                    'psgi.version' => [ 1, 1 ],
-                    'psgi.errors'  => *STDERR,
-                    'psgi.url_scheme' => 'http',
-                    'psgi.run_once'     => Plack::Util::FALSE,
-                    'psgi.multithread'  => Plack::Util::FALSE,
-                    'psgi.multiprocess' => $self->{prefork},
-                    'psgi.streaming'    => Plack::Util::TRUE,
-                    'psgi.nonblocking'  => Plack::Util::FALSE,
-                    'psgix.input.buffered' => Plack::Util::TRUE,
-                    'psgix.io'          => $conn,
-                };
-
-                # no need to take care of pipelining since this module is a HTTP/1.0 server
-                my $may_keepalive = $req_count < $self->{max_keepalive_reqs};
-                if ($may_keepalive && $max_reqs_per_child && $proc_req_count >= $max_reqs_per_child) {
-                    $may_keepalive = undef;
-                }
-                $self->handle_connection($env, $conn, $app, $may_keepalive, $req_count != 1)
-                    or last;
-                # TODO add special cases for clients with broken keep-alive support, as well as disabling keep-alive for HTTP/1.0 proxies
-            }
+            ++$proc_req_count;
+            my $env = {
+                SERVER_PORT => $self->{port},
+                SERVER_NAME => $self->{host},
+                SCRIPT_NAME => '',
+                REMOTE_ADDR => $conn->peerhost,
+                'psgi.version' => [ 1, 1 ],
+                'psgi.errors'  => *STDERR,
+                'psgi.url_scheme' => 'http',
+                'psgi.run_once'     => Plack::Util::FALSE,
+                'psgi.multithread'  => Plack::Util::FALSE,
+                'psgi.multiprocess' => Plack::Util::FALSE,
+                'psgi.streaming'    => Plack::Util::TRUE,
+                'psgi.nonblocking'  => Plack::Util::FALSE,
+                'psgix.input.buffered' => Plack::Util::TRUE,
+                'psgix.io'          => $conn,
+            };
+
+            $self->handle_connection($env, $conn, $app);
             $conn->close;
         }
     }
 }
 
 sub handle_connection {
-    my($self, $env, $conn, $app, $use_keepalive, $is_keepalive) = @_;
+    my($self, $env, $conn, $app) = @_;
 
     my $buf = '';
     my $res = [ 400, [ 'Content-Type' => 'text/plain' ], [ 'Bad Request' ] ];
@@ -161,19 +117,10 @@ sub handle_connection {
     while (1) {
         my $rlen = $self->read_timeout(
             $conn, \$buf, MAX_REQUEST_SIZE - length($buf), length($buf),
-            $is_keepalive ? $self->{keepalive_timeout} : $self->{timeout},
+            $self->{timeout},
         ) or return;
         my $reqlen = parse_http_request($buf, $env);
         if ($reqlen >= 0) {
-            # handle request
-            if ($use_keepalive) {
-                if (my $c = $env->{HTTP_CONNECTION}) {
-                    $use_keepalive = undef
-                        unless $c =~ /^\s*keep-alive\s*/i;
-                } else {
-                    $use_keepalive = undef;
-                }
-            }
             $buf = substr $buf, $reqlen;
             if (my $cl = $env->{CONTENT_LENGTH}) {
                 my $buffer = Plack::TempBuffer->new($cl);
@@ -206,20 +153,20 @@ sub handle_connection {
     }
 
     if (ref $res eq 'ARRAY') {
-        $self->_handle_response($res, $conn, \$use_keepalive);
+        $self->_handle_response($res, $conn);
     } elsif (ref $res eq 'CODE') {
         $res->(sub {
-            $self->_handle_response($_[0], $conn, \$use_keepalive);
+            $self->_handle_response($_[0], $conn);
         });
     } else {
         die "Bad response $res";
     }
 
-    return $use_keepalive;
+    return;
 }
 
 sub _handle_response {
-    my($self, $res, $conn, $use_keepalive_r) = @_;
+    my($self, $res, $conn) = @_;
 
     my @lines = (
         "Date: @{[HTTP::Date::time2str()]}\015\012",
@@ -228,19 +175,9 @@ sub _handle_response {
 
     Plack::Util::header_iter($res->[1], sub {
         my ($k, $v) = @_;
-        if (lc $k eq 'connection') {
-            $$use_keepalive_r = undef
-                if $$use_keepalive_r && lc $v ne 'keep-alive';
-        } else {
-            push @lines, "$k: $v\015\012";
-        }
+        push @lines, "$k: $v\015\012";
     });
-    if ($$use_keepalive_r) {
-        $$use_keepalive_r = undef
-            unless Plack::Util::header_exists($res->[1], 'Content-Length');
-    }
-    push @lines, "Connection: keep-alive\015\012"
-        if $$use_keepalive_r;
+
     unshift @lines, "HTTP/1.0 $res->[0] @{[ HTTP::Status::status_message($res->[0]) ]}\015\012";
     push @lines, "\015\012";
 
@@ -348,8 +285,7 @@ HTTP::Server::PSGI - Standalone PSGI compatible HTTP server
 =head1 DESCRIPTION
 
 HTTP::Server::PSGI is a standalone, single-process and PSGI compatible
-HTTP server implementations. It runs reasonably fast and HTTP/1.0 and
-Keep-Alive requests are supported.
+HTTP server implementations.
 
 This server should be great for the development and testig, but might
 not be suitable for production.
@@ -357,8 +293,10 @@ not be suitable for production.
 Some features in HTTP/1.1, notably chunked requests, responses and
 pipeline requests are B<NOT> supported yet.
 
-See L<Starman> if you want a multi-process prefork server with some
-HTTP/1.1 features support.
+=head1 PREFORKING
+
+L<HTTP::Server::PSGI> does B<NOT> support preforking. See L<Starman>
+or L<Starlet> if you want a multi-process prefork web servers.
 
 =head1 AUTHOR
 
@@ -368,6 +306,6 @@ Tatsuhiko Miyagawa
 
 =head1 SEE ALSO
 
-L<Plack::Handler::Standalone>
+L<Plack::Handler::Standalone> L<Starman> L<Starlet>
 
 =cut
@@ -2,6 +2,7 @@ package Plack::App::URLMap;
 use strict;
 use warnings;
 use parent qw(Plack::Component);
+use constant DEBUG => $ENV{PLACK_URLMAP_DEBUG};
 
 use Carp ();
 
@@ -43,15 +44,21 @@ sub call {
 
     my($http_host, $server_name) = @{$env}{qw( HTTP_HOST SERVER_NAME )};
 
+    if ($http_host and my $port = $env->{SERVER_PORT}) {
+        $http_host =~ s/:$port$//;
+    }
+
     for my $map (@{ $self->{_sorted_mapping} }) {
         my($host, $location, $app) = @$map;
         my $path = $path_info; # copy
         no warnings 'uninitialized';
+        DEBUG && warn "Matching request (Host=$http_host Path=$path) and the map (Host=$host Path=$location)\n";
         next unless not defined $host     or
                     $http_host   eq $host or
                     $server_name eq $host;
         next unless $location eq '' or $path =~ s!^\Q$location\E!!;
         next unless $path eq '' or $path =~ m!^/!;
+        DEBUG && warn "-> Matched!\n";
 
         my $orig_path_info   = $env->{PATH_INFO};
         my $orig_script_name = $env->{SCRIPT_NAME};
@@ -64,6 +71,8 @@ sub call {
         });
     }
 
+    DEBUG && warn "All matching failed.\n";
+
     return [404, [ 'Content-Type' => 'text/plain' ], [ "Not Found" ]];
 }
 
@@ -132,6 +141,12 @@ should also work.
 
 =back
 
+=head1 DEBUGGING
+
+You can set the environment variable C<PLACK_URLMAP_DEBUG> to see how
+this application matches with the incoming request host names and
+paths.
+
 =head1 AUTHOR
 
 Tatsuhiko Miyagawa
@@ -55,7 +55,8 @@ sub response_cb {
                         $line = $filter_cb->($line);
                     }
                     # Send EOF.
-                    push @{ $res->[2] }, $filter_cb->( undef );
+                    my $eof = $filter_cb->( undef );
+                    push @{ $res->[2] }, $eof if defined $eof;
                 } else {
                     my $body    = $res->[2];
                     my $getline = sub { $body->getline };
@@ -136,12 +136,23 @@ Plack::Handler::Apache2 - Apache 2.0 handlers to run PSGI application
   PerlSetVar psgi_app /path/to/app.psgi
   </Location>
 
+  # Optional, preload the application in the parent like startup.pl
   <Perl>
   use Plack::Handler::Apache2;
   Plack::Handler::Apache2->preload("/path/to/app.psgi");
   </Perl>
 
-  # Or create your own handler:
+=head1 DESCRIPTION
+
+This is a handler module to run any PSGI application with mod_perl on Apache 2.x.
+
+=head1 CREATING CUSTOM HANDLER
+
+If you want to create a custom handler that loads or creates PSGI
+applications using other means than loading from C<.psgi> files, you
+can create your own handler class and use C<call_app> class method to
+run your application.
+
   package My::ModPerl::Handler;
   use Plack::Handler::Apache2;
 
@@ -155,19 +166,6 @@ Plack::Handler::Apache2 - Apache 2.0 handlers to run PSGI application
     Plack::Handler::Apache2->call_app($r, $app);
   }
 
-=head1 DESCRIPTION
-
-This is a handler module to run any PSGI application with mod_perl on Apache 2.x.
-
-=head1 METHODS
-
-=head2 call_app($r, $app)
-
-The mod_perl handler in this package loads the app and calls this method.  If
-you'd like to do something different, you can still make use of this module by
-preparing $r and $app in some other fashion and calling this as a class
-method.
-
 =head1 AUTHOR
 
 Tatsuhiko Miyagawa
@@ -87,6 +87,10 @@ package Plack::Handler::CGI;
 1;
 __END__
 
+=head1 NAME
+
+Plack::Handler::CGI - CGI handler for Plack
+
 =head1 SYNOPSIS
 
 Want to run PSGI application as a CGI script? Rename .psgi to .cgi and
@@ -52,7 +52,7 @@ sub run {
     my $proc_manager;
 
     if ($self->{listen}) {
-        $self->daemon_fork if $self->{detach};
+        $self->daemon_fork if $self->{daemonize};
 
         if ($self->{manager}) {
             Plack::Util::load_class($self->{manager});
@@ -88,12 +88,15 @@ sub run {
             'psgi.nonblocking'  => Plack::Util::FALSE,
         };
 
-        # If we're running under Lighttpd, swap PATH_INFO and SCRIPT_NAME if PATH_INFO is empty
-        # http://lists.rawmode.org/pipermail/catalyst/2006-June/008361.html
-        # Thanks to Mark Blythe for this fix
-        if ($env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ /lighttpd/) {
-            $env->{PATH_INFO}   ||= delete $env->{SCRIPT_NAME};
-            $env->{SCRIPT_NAME} ||= '';
+        if ($env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ m!lighttpd[-/]1\.(\d+\.\d+)!) {
+            no warnings;
+            if ($ENV{PLACK_ENV} eq 'development' && $1 < 4.23 && $env->{PATH_INFO} eq '') {
+                warn "You're using lighttpd 1.$1 and appear to mount your FastCGI handler under the root ('/'). ",
+                     "It's known to be causing issues because of the lighttpd bug. You're recommended to enable ",
+                     "LighttpdScriptNameFix middleware, or upgrade lighttpd to 1.4.23 or later and include ",
+                     "'fix-root-scriptname' flag in 'fastcgi.server'. See perldoc Plack::Handler::FCGI for details. ",
+                     "This friendly warning will go away in the next major release of Plack.";
+            }
             $env->{SERVER_NAME} =~ s/:\d+$//; # cut off port number
         }
 
@@ -161,6 +164,10 @@ sub daemon_detach {
 
 __END__
 
+=head1 NAME
+
+Plack::Handler::FCGI - FastCGI handler for Plack
+
 =head1 SYNOPSIS
 
   # Run as a standalone daemon
@@ -276,15 +283,24 @@ See L<http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html#FastCgiExternalSe
 
 =head3 lighttpd
 
-Host in the root path:
+To host the app in the root path, you're recommended to use lighttpd
+1.4.23 or newer with C<fix-root-scriptname> flag like below.
 
-  fastcgi.server = ( "" =>
+  fastcgi.server = ( "/" =>
      ((
        "socket" => "/tmp/fcgi.sock",
        "check-local" => "disable"
+       "fix-root-scriptname" => "enable",
      ))
 
-Or in the non-root path over TCP:
+If you use lighttpd older than 1.4.22 where you don't have
+C<fix-root-scriptname>, mouting apps under the root causes wrong
+C<SCRIPT_NAME> and C<PATH_INFO> set. Also, mouting under the empty
+root (C<"">) or a path that has a trailing slash would still cause
+weird values set even with C<fix-root-scriptname>. In such cases you
+can use L<Plack::Middleware::LighttpdScriptNameFix> to fix it.
+
+To mount in the non-root path over TCP:
 
   fastcgi.server = ( "/foo" =>
      ((
@@ -293,9 +309,10 @@ Or in the non-root path over TCP:
        "check-local" => "disable"
      ))
 
-Plack::Handler::FCGI has a workaround for lighttpd's weird
-C<SCRIPT_NAME> and C<PATH_INFO> setting when you set I<check-local> to
-C<disable> so both configurations (root or non-root) should work fine.
+It's recommended that your mount path does B<NOT> have the trailing
+slash. If you I<really> need to have one, you should consider using
+L<Plack::Middleware::LighttpdScriptNameFix> to fix the wrong
+B<PATH_INFO> values set by lighttpd.
 
 =cut
 
@@ -32,11 +32,13 @@ Plack::Handler::HTTP::Server::PSGI - adapter for HTTP::Server::PSGI
   % plackup -s HTTP::Server::PSGI \
       --host 127.0.0.1 --port 9091 --timeout 120
 
-=head1 CONFIGURATIONS
+=head1 BACKWARD COMPATIBLITY
+
+Since Plack 0.99_22 this handler doesn't support preforking
+configuration i.e. C<--max-workers>. Use L<Starman> or L<Starlet> if
+you need preforking PSGI web server.
 
-This adapter automatically loads Prefork implementation when
-C<max-workers> is set, but otherwise the default HTTP::Server::PSGI
-which is single process.
+=head1 CONFIGURATIONS
 
 =over 4
 
@@ -52,26 +54,10 @@ Port number the server listens on. Defaults to 8080.
 
 Number of seconds a request times out. Defaults to 300.
 
-=item max-keepalive-reqs
-
-Max requests per a keep-alive request. Defaults to 1, which means Keep-alive is off.
-
-=item keepalive-timeout
-
-Number of seconds a keep-alive request times out. Defaults to 2.
-
-=item max-workers
-
-Number of prefork workers. Defaults to 10.
-
 =item max-reqs-per-child
 
 Number of requests per worker to process. Defaults to 100.
 
-=item max-keepalive-reqs
-
-Max requests per a keep-alive request. Defaults to 100.
-
 =back
 
 =head1 AUTHOR
@@ -0,0 +1,285 @@
+package Plack::Handler::Net::FastCGI;
+use strict;
+use Plack::Util;
+use IO::Socket             qw[];
+use Net::FastCGI::Constant qw[:common :type :flag :role :protocol_status];
+use Net::FastCGI::Protocol qw[:all];
+
+sub DEBUG () { 0 }
+
+sub new {
+    my $class = shift;
+    my $self = bless { @_ }, $class;
+    $self->{listen} ||= [ ":$self->{port}" ] if $self->{port};
+    $self->{values} ||= {
+        FCGI_MAX_CONNS   => 1,  # maximum number of concurrent transport connections this application will accept
+        FCGI_MAX_REQS    => 1,  # maximum number of concurrent requests this application will accept
+        FCGI_MPXS_CONNS  => 0,  # this implementation can't multiplex
+    };
+    $self;
+}
+
+sub run {
+    my ($self, $app) = @_;
+    $self->{app} = $app;
+
+    my $socket;
+    my $proto;
+    my $port;
+
+    if ($self->{listen}) {
+        $port = $self->{listen}->[0];
+        if ($port =~ s/^://) {
+            $proto = 'tcp';
+            $socket = IO::Socket::INET->new(
+                Listen    => 5,
+                LocalPort => $port,
+                Reuse     => 1
+            ) or die "Couldn't create listener socket: $!";
+        } else {
+            $proto = 'unix';
+            $socket = IO::Socket::UNIX->new(
+                Listen    => 5,
+                Local     => $port,
+            ) or die "Couldn't create UNIX listener socket: $!";
+        }
+    }
+    else {
+        (-S STDIN)
+          || die "Standard input is not a socket: specify a listen location";
+        $socket = \*STDIN;
+        $socket->autoflush(1);
+    }
+
+    $self->{server_ready}->({
+        host  => 'localhost',
+        port  => $port,
+        proto => $proto,
+        server_software => 'Plack::Handler::Net::FastCGI',
+    }) if $self->{server_ready} && $proto;
+
+    while (my $c = $socket->accept) {
+        $self->process_connection($c);
+    }
+}
+
+sub process_request {
+    my($self, $env, $stdin, $stdout, $stderr) = @_;
+
+    $env = {
+        %$env,
+        'psgi.version'      => [1,1],
+        'psgi.url_scheme'   => ($env->{HTTPS}||'off') =~ /^(?:on|1)$/i ? 'https' : 'http',
+        'psgi.input'        => $stdin,
+        'psgi.errors'       => $stderr,
+        'psgi.multithread'  => Plack::Util::FALSE,
+        'psgi.multiprocess' => Plack::Util::FALSE, # xxx?
+        'psgi.run_once'     => Plack::Util::FALSE,
+        'psgi.streaming'    => Plack::Util::TRUE,
+        'psgi.nonblocking'  => Plack::Util::FALSE,
+    };
+
+    my $res = Plack::Util::run_app $self->{app}, $env;
+
+    if (ref $res eq 'ARRAY') {
+        $self->_handle_response($res, $stdout);
+    } elsif (ref $res eq 'CODE') {
+        $res->(sub {
+            $self->_handle_response($_[0], $stdout);
+        });
+    } else {
+        die "Bad response $res";
+    }
+}
+
+sub _handle_response {
+    my ($self, $res, $stdout) = @_;
+
+    my $hdrs;
+    $hdrs = "Status: $res->[0]\015\012";
+
+    my $headers = $res->[1];
+    while (my ($k, $v) = splice @$headers, 0, 2) {
+        $hdrs .= "$k: $v\015\012";
+    }
+    $hdrs .= "\015\012";
+
+    print {$stdout} $hdrs;
+
+    my $cb = sub { print {$stdout} $_[0] };
+    my $body = $res->[2];
+    if (defined $body) {
+        Plack::Util::foreach($body, $cb);
+    }
+    else {
+        return Plack::Util::inline_object
+            write => $cb,
+            close => sub { };
+    }
+}
+
+sub read_record {
+    @_ == 1 || die(q/Usage: read_record(io)/);
+    my ($io) = @_;
+    no warnings 'uninitialized';
+    read($io, my $header, FCGI_HEADER_LEN) == FCGI_HEADER_LEN
+      || return;
+    my ($type, $request_id, $clen, $plen) = parse_header($header);
+       (!$clen || read($io, my $content, $clen) == $clen)
+    && (!$plen || read($io, my $padding, $plen) == $plen)
+      || return;
+    $content = '' if !$clen;
+    return ($type, $request_id, $content);
+}
+
+sub process_connection {
+    my($self, $socket) = @_;
+
+    my ( $current_id,  # id of the request we are currently processing
+         $stdin,       # buffer for stdin
+         $stdout,      # buffer for stdout
+         $stderr,      # buffer for stderr
+         $params,      # buffer for params (environ)
+         $output,      # buffer for output
+         $done,        # done with connection?
+         $keep_conn ); # more requests on this connection?
+
+    ($current_id, $stdin, $stdout, $stderr) = (0, '', '', '');
+
+    while (!$done) {
+        my ($type, $request_id, $content) = read_record($socket)
+          or last;
+
+        if (DEBUG) {
+            warn '< ', dump_record($type, $request_id, $content), "\n";
+        }
+
+        if ($request_id == FCGI_NULL_REQUEST_ID) {
+            if ($type == FCGI_GET_VALUES) {
+                my $query = parse_params($content);
+                my %reply = map { $_ => $self->{values}->{$_} }
+                            grep { exists $self->{values}->{$_} }
+                            keys %$query;
+                $output = build_record(FCGI_GET_VALUES_RESULT,
+                    FCGI_NULL_REQUEST_ID, build_params(\%reply));
+            }
+            else {
+                $output = build_unknown_type_record($type);
+            }
+        }
+        elsif ($request_id != $current_id && $type != FCGI_BEGIN_REQUEST) {
+            # ignore inactive requests (FastCGI Specification 3.3)
+        }
+        elsif ($type == FCGI_ABORT_REQUEST) {
+            $current_id = 0;
+            ($stdin, $stdout, $stderr, $params) = ('', '', '', '');
+        }
+        elsif ($type == FCGI_BEGIN_REQUEST) {
+            my ($role, $flags) = parse_begin_request_body($content);
+            if ($current_id || $role != FCGI_RESPONDER) {
+                $output = build_end_request_record($request_id, 0, 
+                    $current_id ? FCGI_CANT_MPX_CONN : FCGI_UNKNOWN_ROLE);
+            }
+            else {
+                $current_id = $request_id;
+                $keep_conn  = ($flags & FCGI_KEEP_CONN);
+            }
+        }
+        elsif ($type == FCGI_PARAMS) {
+            $params .= $content;
+        }
+        elsif ($type == FCGI_STDIN) {
+            $stdin .= $content;
+
+            unless (length $content) {
+                open(my $in, '<', \$stdin)
+                  || die(qq/Couldn't open scalar as fh: '$!'/);
+
+                open(my $out, '>', \$stdout)
+                  || die(qq/Couldn't open scalar as fh: '$!'/);
+
+                open(my $err, '>', \$stderr)
+                  || die(qq/Couldn't open scalar as fh: '$!'/);
+
+                $self->process_request(parse_params($params), $in, $out, $err);
+
+                $done   = 1 unless $keep_conn;
+                $output = build_end_request($request_id, 0,
+                    FCGI_REQUEST_COMPLETE, $stdout, $stderr);
+
+                # prepare for next request
+                $current_id = 0;
+                ($stdin, $stdout, $stderr, $params) = ('', '', '', '');
+            }
+        }
+        else {
+            warn(qq/Received an unknown record type '$type'/);
+        }
+
+        if ($output) {
+            print {$socket} $output
+              || die(qq/Couldn't write: '$!'/);
+
+            if (DEBUG) {
+                while (length $output) {
+                    my ($type, $rid, $clen, $plen) = parse_header($output);
+                    my $content = substr($output, FCGI_HEADER_LEN, $clen);
+                    warn '> ', dump_record($type, $rid, $content), "\n";
+                    substr($output, 0, FCGI_HEADER_LEN + $clen + $plen, '');
+                }
+            }
+
+            $output = '';
+        }
+    }
+
+    if (DEBUG && !$done && $!) {
+        warn(qq/Request was prematurely aborted: '$!'/);
+    }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Plack::Handler::Net::FastCGI - FastCGI handler for Plack using Net::FastCGI
+
+=head1 SYNOPSIS
+
+  # Run as a standalone daemon using TCP port
+  plackup -s Net::FastCGI --listen :9090
+
+=head1 DESCRIPTION
+
+This is a handler module to run any PSGI application as a standalone
+FastCGI daemon using L<Net::FastCGI>
+
+=head2 OPTIONS
+
+=over 4
+
+=item listen
+
+    listen => ':8080'
+
+Listen on a socket path, hostname:port, or :port.
+
+=item port
+
+listen via TCP on port on all interfaces (Same as C<< listen => ":$port" >>)
+
+=back
+
+=head1 AUTHORS
+
+Christian Hansesn
+
+Tatsuhiko Miyagawa
+
+=head1 SEE ALSO
+
+L<Plack::Handler::FCGI>
+
+=cut
@@ -0,0 +1,70 @@
+package Plack::Loader::Delayed;
+use strict;
+use parent qw(Plack::Loader);
+
+sub preload_app {
+    my($self, $builder) = @_;
+    $self->{builder} = $builder;
+}
+
+sub run {
+    my($self, $server) = @_;
+
+    my $compiled;
+    my $app = sub {
+        $compiled ||= $self->{builder}->();
+        $compiled->(@_);
+    };
+
+    $server->{psgi_app_builder} = $self->{builder};
+    $server->run($app);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Plack::Loader::Delayed - Delay the loading of .psgi until the first run
+
+=head1 SYNOPSIS
+
+  plackup -s Starlet -L Delayed myapp.psgi
+
+=head1 DESCRIPTION
+
+This loader delays the compilation of specified PSGI application until
+the first request time. This prevents bad things from happening with
+preforking web servers like L<Starlet>, when your application
+manipulates resources such as sockets or database connections in the
+master startup process and then shared by children.
+
+You can combine this loader with C<-M> command line option, like:
+
+  plackup -s Starlet -MCatalyst -L Delayed myapp.psgi
+
+loads the module Catalyst in the master process for the better process
+management with copy-on-write, however the application C<myapp.psgi>
+is loaded per children.
+
+L<Starman> since version 0.2000 loads this loader by default unless
+you specify the command line option C<--preload-app> for the
+L<starman> executable.
+
+=head1 DEVELOPERS
+
+Web server developers can make use of C<psgi_app_builder> attribute
+callback set in Plack::Handler, to load the application earlier than
+the first request time.
+
+=head1 AUTHOR
+
+Tatsuhiko Miyagawa
+
+=head1 SEE ALSO
+
+L<plackup>
+
+=cut
+
@@ -98,7 +98,7 @@ Plack::Loader - (auto)load Plack Servers
   Plack::Loader->auto(%args)->run($app);
 
   # specify the implementation with a name
-  Plack::Loader->load('Standalone::Prefork', %args)->run($app);
+  Plack::Loader->load('FCGI', %args)->run($app);
 
 =head1 DESCRIPTION
 
@@ -13,7 +13,7 @@ sub call {
     my $res = try {
         $self->app->($env);
     } catch {
-        $self->transform_error($_);
+        $self->transform_error($_, $env);
     };
 
     return $res if ref $res eq 'ARRAY';
@@ -29,7 +29,7 @@ sub call {
                 Carp::cluck $_;
                 $writer->close;
             } else {
-                my $res = $self->transform_error($_);
+                my $res = $self->transform_error($_, $env);
                 $respond->($res);
             }
         };
@@ -37,7 +37,7 @@ sub call {
 }
 
 sub transform_error {
-    my($self, $e) = @_;
+    my($self, $e, $env) = @_;
 
     my($code, $message);
     if (blessed $e && $e->can('code')) {
@@ -47,6 +47,7 @@ sub transform_error {
             overload::Method($e, '""') ? "$e"          : undef;
     } else {
         $code = 500;
+        $env->{'psgi.errors'}->print($e);
     }
 
     if ($code !~ /^[3-5]\d\d$/) {
@@ -9,22 +9,18 @@ sub call {
     my $res = $self->app->($env);
     $self->response_cb($res, sub {
         my $res = shift;
-
-        my $h = Plack::Util::headers($res->[1]);
-        if ($h->get('Content-Type') =~ m!/(?:json|javascript)! &&
+        if (defined $res->[2] && ref $res->[2] eq 'ARRAY' && @{$res->[2]} == 1) {
+            my $h = Plack::Util::headers($res->[1]);
+            if ($h->get('Content-Type') =~ m!/(?:json|javascript)! &&
                 $env->{QUERY_STRING} =~ /(?:^|&)callback=([^&]+)/) {
-            # TODO: support callback params other than 'callback'
-            my $cb = URI::Escape::uri_unescape($1);
-
-            if ($cb =~ /^[\w\.\[\]]+$/) {
-                $h->set('Content-Type', 'text/javascript');
-
-                # The filter to transform the body into a JSONP response.
-                my $isnt_first = 0;
-                return sub {
-                    return ( $isnt_first++ ? ''    : "$cb(" )
-                         . ( defined $_[0] ? $_[0] : ')'    );
-                };
+                # TODO: support callback params other than 'callback'
+                my $cb = URI::Escape::uri_unescape($1);
+                if ($cb =~ /^[\w\.\[\]]+$/) {
+                    my $jsonp = "$cb($res->[2][0])";
+                    $res->[2] = [ $jsonp ];
+                    $h->set('Content-Length', length $jsonp);
+                    $h->set('Content-Type', 'text/javascript');
+                }
             }
         }
     });
@@ -44,7 +40,9 @@ Plack::Middleware::JSONP wraps JSON response, which has Content-Type
 value either C<text/javascript> or C<application/json> as a JSONP
 response which is specified with the C<callback> query parameter.
 
-Since this middleware removes the Content-Length header to rewrite the content body, you may also want to enable Plack::Middleware::ContentLength.
+This middleware only works with an application response with content
+body set as a single element array ref and doesn't touch the response
+otherwise.
 
 =head1 AUTHOR
 
@@ -52,7 +50,7 @@ Tatsuhiko Miyagawa
 
 =head1 SEE ALSO
 
-L<Plack> L<Plack::Middleware::ContentLength>
+L<Plack>
 
 =cut
 
@@ -0,0 +1,93 @@
+package Plack::Middleware::LighttpdScriptNameFix;
+use strict;
+use parent qw/Plack::Middleware/;
+use Plack::Util::Accessor qw(script_name);
+
+sub prepare_app {
+    my $self = shift;
+
+    my $script_name = $self->script_name;
+    $script_name = '' unless defined($script_name);
+    $script_name =~ s!/$!!;
+    $self->script_name($script_name);
+}
+
+sub call {
+    my($self, $env) = @_;
+
+    if ($env->{SERVER_SOFTWARE} && $env->{SERVER_SOFTWARE} =~ /lighttpd/) {
+        $env->{PATH_INFO}   = $env->{SCRIPT_NAME} . $env->{PATH_INFO};
+        $env->{SCRIPT_NAME} = $self->script_name;
+        $env->{PATH_INFO}  =~ s/^\Q$env->{SCRIPT_NAME}\E//;
+    }
+
+    return $self->app->($env);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Plack::Middleware::LighttpdScriptNameFix - fixes wrong SCRIPT_NAME and PATH_INFO that lighttpd sets
+
+=head1 SYNOPSIS
+
+  # in your app.psgi
+  use Plack::Builder;
+
+  builder {
+    enable "LighttpdScriptNameFix";
+    $app;
+  };
+
+  # Or from the command line
+  plackup -s FCGI -e 'enable "LighttpdScriptNameFix"' /path/to/app.psgi
+
+=head1 DESCRIPTION
+
+This middleware fixes wrong C<SCRIPT_NAME> and C<PATH_INFO> set by
+lighttpd when you mount your app under the root path ("/"). If you use
+lighttpd 1.4.23 or later you can instead enable C<fix-root-scriptname>
+flag inside C<fastcgi.server> instead of using this middleware.
+
+=head1 CONFIGURATION
+
+=over 4
+
+=item script_name
+
+Even with C<fix-root-scriptname>, lighttpd I<still> sets weird
+C<SCRIPT_NAME> and C<PATH_INFO> if you mount your application at C<"">
+or something that ends with C</>. Setting C<script_name> option tells
+the middleware how to reconstruct the new correct C<SCRIPT_NAME> and
+C<PATH_INFO>.
+
+If you mount the app under C</something/>, you should set:
+
+  enable "LighttpdScriptNameFix", script_name => "/something";
+
+and when a request for C</something/a/b?param=1> comes, C<SCRIPT_NAME>
+becomes C</something> and C<PATH_INFO> becomes C</a/b>.
+
+C<script_name> option is set to empty by default, which means all the
+request path is set to C<PATH_INFO> and it behaves like your fastcgi
+application is mounted in the root path.
+
+=back
+
+=head1 AUTHORS
+
+Yury Zavarin
+
+Tatsuhiko Miyagawa
+
+=head1 SEE ALSO
+
+L<Plack::Handler::FCGI>
+L<http://github.com/miyagawa/Plack/issues#issue/68>
+L<https://redmine.lighttpd.net/issues/729>
+
+=cut
+
@@ -6,6 +6,16 @@ use parent qw(Plack::Middleware);
 use Scalar::Util qw(blessed);
 use Plack::Util;
 
+sub wrap {
+    my($self, $app) = @_;
+
+    unless (ref $app eq 'CODE' or overload::Method($app, '&{}')) {
+        Carp::croak("PSGI app should be a code reference: ", (defined $app ? $app : "undef"));
+    }
+
+    $self->SUPER::wrap($app);
+}
+
 sub call {
     my $self = shift;
     my $env = shift;
@@ -79,7 +89,7 @@ sub validate_res {
     my $croak = $streaming ? \&Carp::confess : \&Carp::croak;
 
     unless (ref($res) and ref($res) eq 'ARRAY' || ref($res) eq 'CODE') {
-        $croak->('response should be arrayref or coderef');
+        $croak->('response should be array ref or code ref');
     }
 
     if (ref $res eq 'CODE') {
@@ -127,12 +137,18 @@ Plack::Middleware::Lint - Validate request and response
   my $app = sub { ... }; # your app or middleware
   $app = Plack::Middleware::Lint->wrap($app);
 
+  # Or from plackup
+  plackup -e 'enable "Lint"' myapp.psgi
+
 =head1 DESCRIPTION
 
 Plack::Middleware::Lint is a middleware component to validate request
-and response environment. You are strongly suggested to use enable
-this middleware when you develop a framework adapter or a new server
-that implements PSGI interface.
+and response environment formats. You are strongly suggested to use
+this middleware when you develop a new framework adapter or a new PSGI
+web server that implements the PSGI interface.
+
+This middleware is enabled by default when you run plackup or other
+launcher tools with the default environment I<development> value.
 
 =head1 AUTHOR
 
@@ -140,5 +156,9 @@ Tatsuhiko Miyagawa
 
 Tokuhiro Matsuno
 
+=head1 SEE ALSO
+
+L<Plack>
+
 =cut
 
@@ -21,6 +21,8 @@ sub call {
     $env->{'psgix.logger'} = sub {
         my $args = shift;
         my $level = $args->{level};
+        local $Log::Log4perl::caller_depth
+            = $Log::Log4perl::caller_depth + 1;
         $self->logger->$level($args->{message});
     };
 
@@ -5,11 +5,12 @@ use parent qw/Plack::Middleware/;
 use Devel::StackTrace;
 use Devel::StackTrace::AsHTML;
 use Try::Tiny;
+use Plack::Util::Accessor qw( force );
 
 our $StackTraceClass = "Devel::StackTrace";
 
 # Optional since it needs PadWalker
-if (try { require Devel::StackTrace::WithLexicals; 1 }) {
+if ($ENV{PLACK_STACKTRACE_LEXICALS} && try { require Devel::StackTrace::WithLexicals; 1 }) {
     $StackTraceClass = "Devel::StackTrace::WithLexicals";
 }
 
@@ -22,13 +23,14 @@ sub call {
         die @_;
     };
 
-    my $res = try { $self->app->($env) };
+    my $caught;
+    my $res = try { $self->app->($env) } catch { $caught = $_ };
 
-    if ($trace && (!$res or $res->[0] == 500)) {
+    if ($trace && ($caught || $self->{force} && ref $res eq 'ARRAY' && $res->[0] == 500) ) {
         if (($env->{HTTP_ACCEPT} || '*/*') =~ /html/) {
-            $res = [500, ['Content-Type' => 'text/html; charset=utf-8'], [ $trace->as_html ]];
+            $res = [500, ['Content-Type' => 'text/html; charset=utf-8'], [ utf8_safe($trace->as_html) ]];
         } else {
-            $res = [500, ['Content-Type' => 'text/plain; charset=utf-8'], [ $trace->as_string ]];
+            $res = [500, ['Content-Type' => 'text/plain; charset=utf-8'], [ utf8_safe($trace->as_string) ]];
         }
     }
 
@@ -40,6 +42,22 @@ sub call {
     return $res;
 }
 
+sub utf8_safe {
+    my $str = shift;
+
+    # NOTE: I know messing with utf8:: in the code is WRONG, but
+    # because we're running someone else's code that we can't
+    # guarnatee which encoding an exception is encoded, there's no
+    # better way than doing this. The latest Devel::StackTrace::AsHTML
+    # (0.08 or later) encodes high-bit chars as HTML entities, so this
+    # path won't be executed.
+    if (utf8::is_utf8($str)) {
+        utf8::encode($str);
+    }
+
+    $str;
+}
+
 1;
 
 __END__
@@ -50,7 +68,7 @@ Plack::Middleware::StackTrace - Displays stack trace when your app dies
 
 =head1 SYNOPSIS
 
-  enable "Plack::Middleware::StackTrace";
+  enable "StackTrace";
 
 =head1 DESCRIPTION
 
@@ -58,11 +76,37 @@ This middleware catches exceptions (run-time errors) happening in your
 application and displays nice stack trace screen.
 
 This middleware is enabled by default when you run L<plackup> in the
-default development mode.
+default I<development> mode.
+
+You're recommended to use this middleware during the development and
+use L<Plack::Middleware::HTTPExceptions> in the deployment mode as a
+replacement, so that all the exceptions thrown from your application
+still get caught and rendered as a 500 error response, rather than
+crashing the web server.
+
+Catching errors in streaming response is not supported.
 
 =head1 CONFIGURATION
 
-No configuration option is available.
+=over 4
+
+=item force
+
+  enable "StackTrace", force => 1;
+
+Force display the stack trace when an error occurs within your
+application and the response code from your application is
+500. Defaults to off.
+
+The use case of this option is that when your framework catches all
+the exceptions in the main handler and returns all failures in your
+code as a normal 500 PSGI error response. In such cases, this
+middleware would never have a chance to display errors because it
+can't tell if it's an application error or just random C<eval> in your
+code. This option enforces the middleware to display stack trace even
+if it's not the direct error thrown by the application.
+
+=back
 
 =head1 AUTHOR
 
@@ -72,7 +116,7 @@ Tatsuhiko Miyagawa
 
 =head1 SEE ALSO
 
-L<Devel::StackTrace::AsHTML> L<Plack::Middleware>
+L<Devel::StackTrace::AsHTML> L<Plack::Middleware> L<Plack::Middleware::HTTPExceptions>
 
 =cut
 
@@ -2,7 +2,7 @@ package Plack::Request;
 use strict;
 use warnings;
 use 5.008_001;
-our $VERSION = '0.9920';
+our $VERSION = '0.9933';
 $VERSION = eval $VERSION;
 
 use HTTP::Headers;
@@ -46,6 +46,9 @@ sub secure      { $_[0]->scheme eq 'https' }
 sub body        { $_[0]->env->{'psgi.input'} }
 sub input       { $_[0]->env->{'psgi.input'} }
 
+sub content_length   { $_[0]->env->{CONTENT_LENGTH} }
+sub content_type     { $_[0]->env->{CONTENT_TYPE} }
+
 sub session         { $_[0]->env->{'psgix.session'} }
 sub session_options { $_[0]->env->{'psgix.session.options'} }
 sub logger          { $_[0]->env->{'psgix.logger'} }
@@ -90,9 +93,9 @@ sub content {
         $self->_parse_request_body;
     }
 
-    my $fh = $self->input          or return '';
-    my $cl = $self->content_length or return '';
-    $fh->read(my($content), $self->content_length || 0, 0);
+    my $fh = $self->input                 or return '';
+    my $cl = $self->env->{CONTENT_LENGTH} or return'';
+    $fh->read(my($content), $cl, 0);
     $fh->seek(0, 0);
 
     return $content;
@@ -116,10 +119,8 @@ sub headers {
     }
     $self->{headers};
 }
-# shortcut
+
 sub content_encoding { shift->headers->content_encoding(@_) }
-sub content_length   { shift->headers->content_length(@_) }
-sub content_type     { shift->headers->content_type(@_) }
 sub header           { shift->headers->header(@_) }
 sub referer          { shift->headers->referer(@_) }
 sub user_agent       { shift->headers->user_agent(@_) }
@@ -252,7 +253,6 @@ sub _parse_request_body {
         return;
     }
 
-    # Do not use ->content_type to get multipart boundary correctly
     my $body = HTTP::Body->new($ct, $cl);
 
     my $input = $self->input;
@@ -1,7 +1,7 @@
 package Plack::Response;
 use strict;
 use warnings;
-our $VERSION = '0.9920';
+our $VERSION = '0.9933';
 $VERSION = eval $VERSION;
 
 use Plack::Util::Accessor qw(body status);
@@ -28,8 +28,8 @@ sub parse_options {
 
     local @ARGV = @_;
 
-    # From 'prove': Allow cuddling the paths with -I and -M
-    @ARGV = map { /^(-[IM])(.+)/ ? ($1,$2) : $_ } @ARGV;
+    # From 'prove': Allow cuddling the paths with -I, -M and -e
+    @ARGV = map { /^(-[IMe])(.+)/ ? ($1,$2) : $_ } @ARGV;
 
     my($host, $port, $socket, @listen);
 
@@ -50,7 +50,8 @@ sub parse_options {
         'r|reload'     => sub { $self->{loader} = "Restarter" },
         'R|Reload=s'   => sub { $self->{loader} = "Restarter"; $self->loader->watch(split ",", $_[1]) },
         'L|loader=s'   => \$self->{loader},
-        "h|help",      => \$self->{help},
+        "h|help"       => \$self->{help},
+        "v|version"    => \$self->{version},
     );
 
     my(@options, @argv);
@@ -60,8 +61,10 @@ sub parse_options {
             $v[0] =~ tr/-/_/;
             if (@v == 2) {
                 push @options, @v;
+            } elsif ($v[0] =~ s/^(disable|enable)_//) {
+                push @options, $v[0], $1 eq 'enable';
             } else {
-                push @options, @v, shift @ARGV;
+                push @options, $v[0], shift @ARGV;
             }
         } else {
             push @argv, $_;
@@ -104,6 +107,14 @@ sub mangle_host_port_socket {
     return host => $host, port => $port, listen => \@listen, socket => $socket;
 }
 
+sub version_cb {
+    my $self = shift;
+    $self->{version_cb} || sub {
+        require Plack;
+        print "Plack $Plack::VERSION\n";
+    };
+}
+
 sub setup {
     my $self = shift;
 
@@ -112,6 +123,11 @@ sub setup {
         Pod::Usage::pod2usage(0);
     }
 
+    if ($self->{version}) {
+        $self->version_cb->();
+        exit;
+    }
+
     lib->import(@{$self->{includes}}) if @{$self->{includes}};
 
     if ($self->{eval}) {
@@ -160,21 +176,28 @@ sub watch {
         if $self->{loader} eq 'Restarter';
 }
 
+sub apply_middleware {
+    my($self, $app, $class, @args) = @_;
+
+    my $mw_class = Plack::Util::load_class($class, 'Plack::Middleware');
+    build { $mw_class->wrap($_[0], @args) } $app;
+}
+
 sub prepare_devel {
     my($self, $app) = @_;
 
-    require Plack::Middleware::StackTrace;
-    require Plack::Middleware::AccessLog;
-    $app = build { Plack::Middleware::StackTrace->wrap($_[0]) } $app;
+    $app = $self->apply_middleware($app, 'Lint');
+    $app = $self->apply_middleware($app, 'StackTrace');
     unless ($ENV{GATEWAY_INTERFACE}) {
-        $app = build { Plack::Middleware::AccessLog->wrap($_[0], logger => sub { print STDERR @_ }) } $app;
+        $app = $self->apply_middleware($app, 'AccessLog', logger => sub { print STDERR @_ });
     }
 
     push @{$self->{options}}, server_ready => sub {
         my($args) = @_;
-        my $name = $args->{server_software} || ref($args); # $args is $server
-        my $host = $args->{host} || 0;
-        print STDERR "$name: Accepting connections at http://$host:$args->{port}/\n";
+        my $name  = $args->{server_software} || ref($args); # $args is $server
+        my $host  = $args->{host} || 0;
+        my $proto = $args->{proto} || 'http';
+        print STDERR "$name: Accepting connections at $proto://$host:$args->{port}/\n";
     };
 
     $app;
@@ -1,6 +1,6 @@
 package Plack::Server::ServerSimple;
 use strict;
-our $VERSION = '0.9920';
+our $VERSION = '0.9933';
 $VERSION = eval $VERSION;
 
 use parent qw(Plack::Handler::HTTP::Server::Simple);
@@ -19,6 +19,10 @@ Plack::Server::Standalone::Prefork - DEPRECATED
 
 =head1 DESCRIPTION
 
-B<This module is deprecated>. See L<Plack::Handler::Standalone>.
+B<This module is deprecated>.
+
+=head1 SEE ALSO
+
+L<HTTP::Server::PSGI> L<Starman> L<Starlet>
 
 =cut
@@ -161,15 +161,15 @@ our @TEST = (
         'bigger file',
         sub {
             my $cb  = shift;
-            my $res = $cb->(GET "http://127.0.0.1/kyoto.jpg");
+            my $res = $cb->(GET "http://127.0.0.1/baybridge.jpg");
             is $res->code, 200;
             is $res->header('content_type'), 'image/jpeg';
-            is length $res->content, 2397701;
-            is Digest::MD5::md5_hex($res->content), '9c6d7249a77204a88be72e9b2fe279e8';
+            is length $res->content, 79838;
+            is Digest::MD5::md5_hex($res->content), '983726ae0e4ce5081bef5fb2b7216950';
         },
         sub {
             my $env = shift;
-            open my $fh, '<', "$share_dir/kyoto.jpg";
+            open my $fh, '<', "$share_dir/baybridge.jpg";
             binmode $fh;
             return [
                 200,
@@ -308,12 +308,7 @@ our @TEST = (
         },
     ],
     [
-        # PEP-333 says:
-        #    If the iterable returned by the application has a close() method,
-        #   the server or gateway must call that method upon completion of the
-        #   current request, whether the request was completed normally, or
-        #   terminated early due to an error. 
-        'call close after read file-like',
+        'call close after read IO::Handle-like',
         sub {
             my $cb  = shift;
             my $res = $cb->(GET "http://127.0.0.1/call_close");
@@ -322,14 +317,13 @@ our @TEST = (
         sub {
             my $env = shift;
             {
-                package CalledClose;
                 our $closed = -1;
-                sub new { $closed = 0; my $i=0; bless \$i, 'CalledClose' }
-                sub getline {
+                sub CalledClose::new { $closed = 0; my $i=0; bless \$i, 'CalledClose' }
+                sub CalledClose::getline {
                     my $self = shift;
                     return $$self++ < 4 ? $$self : undef;
                 }
-                sub close     { ::ok(1, 'closed') if defined &::ok }
+                sub CalledClose::close { ::ok(1, 'closed') if defined &::ok }
             }
             return [
                 200,
@@ -679,13 +673,29 @@ sub test_app_handler {
 1;
 __END__
 
+=head1 NAME
+
+Plack::Test::Suite - Test suite for Plack handlers
+
 =head1 SYNOPSIS
 
-  # TBD See t/Plack-Servet/*.t for now
+  use Test::More;
+  use Plack::Test::Suite;
+  Plack::Test::Suite->run_server_tests('Your::Handler');
+  done_testing;
 
 =head1 DESCRIPTION
 
-Plack::Test::Suite is a test suite to test a new PSGI server implementation.
+Plack::Test::Suite is a test suite to test a new PSGI server
+implementation. It automatically loads a new handler environment and
+uses LWP to send HTTP requests to the local server to make sure your
+handler implements the PSGI specification correctly.
+
+Note that the handler name doesn't include the C<Plack::Handler::>
+prefix, i.e. if you have a new Plack handler Plack::Handler::Foo, your
+test script would look like:
+
+  Plack::Test::Suite->run_server_tests('Foo');
 
 =head1 AUTHOR
 
@@ -105,7 +105,14 @@ sub _load_sandbox {
     my $_package = $_file;
     $_package =~ s/([^A-Za-z0-9_])/sprintf("_%2x", unpack("C", $1))/eg;
 
-    eval "package Plack::Sandbox::$_package; do(\$_file) or die(\$\@ || \$!)";
+    return eval sprintf <<'END_EVAL', $_package;
+package Plack::Sandbox::%s;
+{
+    my $app = do $_file;
+    if ( !$app && ( my $error = $@ || $! )) { die $error; }
+    $app;
+}
+END_EVAL
 }
 
 sub load_psgi {
@@ -115,14 +122,10 @@ sub load_psgi {
 
     my $file = $stuff =~ /^[a-zA-Z0-9\_\:]+$/ ? class_to_file($stuff) : $stuff;
     my $app = _load_sandbox($file);
-    return $app->to_app if $app and Scalar::Util::blessed($app) and $app->can('to_app');
-    return $app if $app and (ref $app eq 'CODE' or overload::Method($app, '&{}'));
+    die "Error while loading $file: $@" if $@;
 
-    if (my $e = $@ || $!) {
-        die "Can't load $file: $e";
-    } else {
-        Carp::croak("$file doesn't return PSGI app handler: " . ($app || undef));
-    }
+    return $app->to_app if $app and Scalar::Util::blessed($app) and $app->can('to_app');
+    return $app;
 }
 
 sub run_app($$) {
@@ -3,7 +3,7 @@ package Plack;
 use strict;
 use warnings;
 use 5.008_001;
-our $VERSION = '0.9920';
+our $VERSION = '0.9933';
 $VERSION = eval $VERSION;
 
 1;
@@ -27,16 +27,23 @@ PSGI and Plack are and why we need them.
 =head2 Plack::Handler
 
 L<Plack::Handler> and its subclasses contains adapters for web
-servers. We have adapters for Standalone, CGI, FCGI, Apache, AnyEvent,
-Coro, Danga::Socket and many server environments that you can run PSGI
-applications on.
+servers. We have adapters for the built-in standalone web server
+L<HTTP::Server::PSGI>, L<CGI|Plack::Handler::CGI>,
+L<FCGI|Plack::Handler::FCGI>, L<Apache1|Plack::Handler::Apache1>,
+L<Apache2|Plack::Handler::Apache2>,
+L<Net::FastCGI|Plack::Handler::Net::FastCGI> and
+L<HTTP::Server::Simple|Plack::Handler::HTTP::Server::Simple> included
+in the core Plack distribution.
+
+There are also many HTTP server implementations on CPAN that has Plack
+handlers.
 
 See L<Plack::Handler> how to write your own adapters.
 
 =head2 Plack::Loader
 
-L<Plack::Loader> is a loader to load one of Plack::Server adapters and
-run PSGI application code reference with it.
+L<Plack::Loader> is a loader to load one of L<Plack::Handler> adapters
+and run PSGI application code reference with it.
 
 =head2 Plack::Util
 
@@ -120,8 +127,13 @@ L<Plack::Test::Suite> is a test suite to test a new PSGI server backend.
 =head2 Patches and Bug Fixes
 
 Small patches and bug fixes can be either submitted via nopaste on IRC
-L<irc://irc.perl.org/#plack> or email. You could also fork on github
-(http://github.com/miyagawa/Plack) to make larger fixes.
+L<irc://irc.perl.org/#plack> or L<the github issue
+tracker|http://github.com/miyagawa/Plack/issues>.  Forking on
+L<github|http://github.com/miyagawa/Plack> is another good way if you
+intend to make larger fixes.
+
+See also L<http://contributing.appspot.com/plack> when you think this
+document is terribly outdated.
 
 =head2 Module Namespaces
 
@@ -148,14 +160,14 @@ framework. It's like naming your application under CGI:: namespace if
 it's supposed to run on CGI and that is a really bad choice and
 confuse people.
 
-=head1 COPYRIGHT
-
-Copyright 2009- Tatsuhiko Miyagawa
-
 =head1 AUTHOR
 
 Tatsuhiko Miyagawa
 
+=head1 COPYRIGHT
+
+Copyright 2009-2010 Tatsuhiko Miyagawa
+
 =head1 CONTRIBUTORS
 
 Yuval Kogman (nothingmuch)
@@ -164,7 +176,7 @@ Tokuhiro Matsuno (tokuhirom)
 
 Kazuhiro Osawa (Yappo)
 
-Kzzuho Oku
+Kazuho Oku
 
 Florian Ragwitz (rafl)
 
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!perl
 use strict;
 use lib "lib";
 use Plack::Runner;
@@ -96,7 +96,7 @@ TCP socket.
 
 Select a specific implementation to run on using the C<PLACK_SERVER>
 environment variable or use the C<-s> or C<--server> flag which will
-be prefered over the environment variable if present.
+be preferred over the environment variable if present.
 
 =item -S, --socket
 
@@ -137,8 +137,8 @@ environment setting the application is running on.
 The value can be anything but commonly used ones are C<development>,
 C<deployment> and C<test>.
 
-If it's set to C<development>, following middleware is enabled by
-default: L<AccessLog>, L<StackTrace>.
+If it's set to C<development>, following middleware components are
+enabled by default: I<AccessLog>, I<StackTrace> and I<Lint>.
 
 =item -r, --reload
 
@@ -158,12 +158,16 @@ separated by comma (C<,>).
 
 Specify the server loading subclass that implements how to run the
 server. Available options are I<Plack::Loader> (default), I<Restarter>
-(automatically set when C<-r> or C<-R> is used) and I<Shotgun>.
+(automatically set when C<-r> or C<-R> is used), I<Delayed> and
+I<Shotgun>.
+
+See L<Plack::Loader::Delayed> and L<Plack::Loader::Shotgun> when to
+use those loader types.
 
 =back
 
 Other options that starts with C<--> are passed through to the backend
-server. See each Plack::Server backend documentations to see which
+server. See each Plack::Handler backend documentations to see which
 options are available.
 
 =head1 SEE ALSO
diff --git a/var/tmp/source/MIYAGAWA/Plack-0.9933/Plack-0.9933/share/baybridge.jpg b/var/tmp/source/MIYAGAWA/Plack-0.9933/Plack-0.9933/share/baybridge.jpg
new file mode 100644
index 00000000..484bcda9
Binary files /dev/null and b/var/tmp/source/MIYAGAWA/Plack-0.9933/Plack-0.9933/share/baybridge.jpg differ
diff --git a/var/tmp/source/MIYAGAWA/Plack-0.9920/Plack-0.9920/share/kyoto.jpg b/var/tmp/source/MIYAGAWA/Plack-0.9920/Plack-0.9920/share/kyoto.jpg
deleted file mode 100644
index 05ad1992..00000000
Binary files a/var/tmp/source/MIYAGAWA/Plack-0.9920/Plack-0.9920/share/kyoto.jpg and /dev/null differ
@@ -53,11 +53,18 @@ sub test_lighty_external (&@) {
     plan skip_all => 'Please set LIGHTTPD_BIN to the path to lighttpd'
         unless $lighttpd_bin && -x $lighttpd_bin;
 
+    my $ver = (`$lighttpd_bin -v` =~ m!lighttpd[-/]1.(\d+\.\d+)!)[0];
+    if ($ver < 4.17) {
+        plan skip_all => "Too old lighttpd (1.$ver), known to be broken";
+    }
+
+    diag "Testing with lighttpd 1.$ver";
+
     my $tmpdir = File::Temp::tempdir( CLEANUP => 1 );
 
     test_tcp(
         client => sub {
-            $callback->($lighty_port, $fcgi_port);
+            $callback->($lighty_port, $fcgi_port, ($ver && $ver < 4.23));
             warn `cat $tmpdir/error.log` if $ENV{DEBUG};
         },
         server => sub {
@@ -98,11 +105,12 @@ server.port = $port
 
 # HTTP::Engine app specific fcgi setup
 fastcgi.server = (
-    "" => ((
+    "/" => ((
             "check-local"     => "disable",
             "host"            => "127.0.0.1",
             "port"            => $fcgiport,
             "idle-timeout"    => 20,
+            "fix-root-scriptname" => "enable", # for 1.4.23 or later
     ))
 )
 END
@@ -12,24 +12,32 @@ my $fcgi_port;
 
 test_lighty_external(
    sub {
-       ($lighty_port, $fcgi_port) = @_;
-       Plack::Test::Suite->run_server_tests(\&run_server, $fcgi_port, $lighty_port);
+       ($lighty_port, $fcgi_port, my $needs_fix) = @_;
+       Plack::Test::Suite->run_server_tests(run_server_cb($needs_fix), $fcgi_port, $lighty_port);
        done_testing();
     }
 );
 
-sub run_server {
-    my($port, $app) = @_;
+sub run_server_cb {
+    my $needs_fix = shift;
 
-    $| = 0; # Test::Builder autoflushes this. reset!
+    require Plack::Middleware::LighttpdScriptNameFix;
+    return sub {
+        my($port, $app) = @_;
 
-    my $server = Plack::Handler::FCGI->new(
-        host        => '127.0.0.1',
-        port        => $port,
-        manager     => '',
-        keep_stderr => 1,
-    );
-    $server->run($app);
+        note "Applying LighttpdScriptNameFix" if $needs_fix;
+        $app = Plack::Middleware::LighttpdScriptNameFix->wrap($app) if $needs_fix;
+
+        $| = 0; # Test::Builder autoflushes this. reset!
+
+        my $server = Plack::Handler::FCGI->new(
+            host        => '127.0.0.1',
+            port        => $port,
+            manager     => '',
+            keep_stderr => 1,
+        );
+        $server->run($app);
+    };
 }
 
 
@@ -0,0 +1,36 @@
+use strict;
+use warnings;
+use Test::More;
+use Test::Requires { 'Net::FastCGI' => 0.11, 'FCGI::Client' => 0.04 };
+use Plack::Handler::Net::FastCGI;
+use Test::TCP;
+use Plack::Test::Suite;
+use t::FCGIUtils;
+
+plan skip_all => "Set TEST_FCGI_CLIENT to test this"
+    unless $ENV{TEST_FCGI_CLIENT};
+
+my $http_port;
+my $fcgi_port;
+
+test_fcgi_standalone(
+   sub {
+       ($http_port, $fcgi_port) = @_;
+       Plack::Test::Suite->run_server_tests(\&run_server, $fcgi_port, $http_port);
+       done_testing();
+    }
+);
+
+sub run_server {
+    my($port, $app) = @_;
+
+    $| = 0; # Test::Builder autoflushes this. reset!
+
+    my $server = Plack::Handler::Net::FastCGI->new(
+        host        => '127.0.0.1',
+        port        => $port,
+    );
+    $server->run($app);
+}
+
+
@@ -1,15 +0,0 @@
-use strict;
-use warnings;
-use Test::More;
-use Test::Requires {
-    'HTTP::Parser::XS' => 0,
-    'Parallel::Prefork' => 0.04,
-};
-
-use FindBin;
-use Plack;
-use Plack::Test::Suite;
-
-Plack::Test::Suite->run_server_tests('Standalone', undef, undef, max_workers => 10);
-done_testing();
-
@@ -1,4 +1,5 @@
 use strict;
+no warnings 'redefine';
 use Test::More;
 use Plack::Loader;
 
@@ -0,0 +1,28 @@
+use strict;
+use Test::More;
+use Plack::Loader;
+
+my $compiled;
+
+my $builder = sub {
+    $compiled = 1;
+    my $app = sub {
+        return [ 200, [], [ "Hi" ] ];
+    };
+};
+
+# The following eval might not fail if you set PLACK_SEVER
+delete $ENV{PLACK_SERVER};
+
+eval {
+    my $loader = Plack::Loader::Delayed->new;
+    $loader->preload_app($builder);
+    my $server = $loader->auto;
+    ok(!$compiled);
+};
+
+ok 1 if $@;
+
+done_testing;
+
+
@@ -0,0 +1,62 @@
+use strict;
+use Test::Requires qw(IO::Handle::Util);
+
+package MyComponent;
+use parent 'Plack::Component';
+use Plack::Util::Accessor qw( res cb );
+
+sub call { return $_[0]->response_cb( $_[0]->res, $_[0]->cb ); }
+
+package main;
+use IO::Handle::Util qw(:io_from);
+use HTTP::Request::Common;
+use Test::More;
+use Plack::Test;
+
+# Various kinds of PSGI responses.
+sub generate_responses {
+    [200, ['Content-Type' => 'text/plain'], ['Hello']],
+    [200, ['Content-Type' => 'text/plain'], io_from_array ['Hello']],
+    sub { $_[0]->([ 200, ['Content-Type' => 'text/plain'], ['Hello'] ]) },
+    sub {
+        my $writer = $_[0]->([ 200, ['Content-Type' => 'text/plain'] ]);
+        $writer->write( 'Hello' );
+        $writer->close;
+    },
+}
+
+# $body filters can return undef with no warnings.
+for my $res ( generate_responses ) {
+    my @warns;
+    local $SIG{__WARN__} = sub { push @warns, @_ };
+
+    my $app = MyComponent->new(
+        res => $res, cb => sub { sub { $_[0] } },
+    );
+    test_psgi( $app, sub { $_[0]->(GET '/') } );
+
+    is_deeply \@warns, [];
+}
+
+for my $res ( generate_responses ) {
+    my $app = MyComponent->new(
+        res => $res, cb => sub {
+            my $done;
+            sub {
+                return if $done;
+                if (defined $_[0]) {
+                    return $_[0];
+                } else {
+                    $done = 1;
+                    return 'END';
+                }
+            },
+        },
+    );
+    test_psgi( $app, sub {
+        my $res = $_[0]->(GET '/');
+        is $res->content, 'HelloEND';
+    } );
+}
+
+done_testing;
@@ -10,11 +10,11 @@ my @tests = (
     },
     {
         app => sub {
-            open my $fh, "<", "share/kyoto.jpg";
+            open my $fh, "<", "share/baybridge.jpg";
             [ 200, [ 'Content-Type' => 'image/jpeg' ], $fh ];
         },
         env => { REQUEST_METHOD => 'GET' },
-        headers => [ 'Content-Type' => 'image/jpeg', 'Content-Length' => 2397701 ],
+        headers => [ 'Content-Type' => 'image/jpeg', 'Content-Length' => 79838 ],
     },
     {
         app => sub {
@@ -17,16 +17,6 @@ my @app = (
             );
         };
     },
-    sub {
-        return sub {
-            my $respond = shift;
-            my $writer = $respond->(
-                [ 200, [ 'Content-Type' => 'application/json' ] ],
-            );
-            $writer->write( $json );
-            $writer->close;
-        };
-    },
 );
 
 for my $app ( @app ) {
@@ -1,6 +1,6 @@
 use strict;
 use Plack::Test;
-use Test::Requires qw(Log::Dispatch::Array);
+use Test::Requires { 'Log::Dispatch' => 2.25, 'Log::Dispatch::Array' => 1.001 };
 
 use Test::More;
 use Plack::Middleware::LogDispatch;
@@ -0,0 +1,39 @@
+use strict;
+use warnings;
+use Test::More;
+use Plack::Middleware::StackTrace;
+use Plack::Test;
+use HTTP::Request::Common;
+
+my $app = sub {
+    eval { die "Blah" };
+
+    return [ 500, [ 'Content-Type', 'text/html' ], [ "Fancy Error" ] ];
+};
+
+my $default_app = Plack::Middleware::StackTrace->wrap($app);
+
+test_psgi $default_app, sub {
+    my $cb = shift;
+
+    my $req = GET "/";
+    my $res = $cb->($req);
+
+    is $res->code, 500;
+    like $res->content, qr/Fancy Error/;
+};
+
+my $force_app = Plack::Middleware::StackTrace->wrap($app, force => 1);
+
+test_psgi $force_app, sub {
+    my $cb = shift;
+
+    my $req = GET "/";
+    my $res = $cb->($req);
+
+    is $res->code, 500;
+    like $res->content, qr/Blah/;
+};
+
+done_testing;
+
@@ -0,0 +1,30 @@
+use strict;
+use warnings;
+use Test::More;
+use Plack::Middleware::StackTrace;
+use Plack::Test;
+use HTTP::Request::Common;
+
+my $app = sub {
+    eval { require DooBar };
+
+    return sub {
+        my $respond = shift;
+        $respond->([ 200, [ "Content-Type", "text/plain" ], [ "Hello World" ] ]);
+    };
+};
+
+$app = Plack::Middleware::StackTrace->wrap($app);
+
+test_psgi $app, sub {
+    my $cb = shift;
+
+    my $req = GET "/";
+    my $res = $cb->($req);
+
+    ok $res->is_success;
+    like $res->content, qr/Hello World/;
+};
+
+done_testing;
+
@@ -0,0 +1,28 @@
+use strict;
+use warnings;
+use Test::More;
+use Test::Requires { 'Devel::StackTrace::AsHTML' => 0.08 };
+use Plack::Middleware::StackTrace;
+use Plack::Test;
+use HTTP::Request::Common;
+
+$Plack::Test::Impl = "Server";
+my $app = Plack::Middleware::StackTrace->wrap(sub { die "Foo \x{30c6}" });
+
+test_psgi $app, sub {
+    my $cb = shift;
+
+    my $req = GET "/";
+    $req->header(Accept => "text/html,*/*");
+    my $res = $cb->($req);
+
+    like $res->content, qr/Foo &#12486;/;
+
+    $req = GET "/";
+    $res = $cb->($req);
+    is $res->code, 500;
+    like $res->content, qr/Foo/;
+};
+
+done_testing;
+
@@ -0,0 +1,33 @@
+use strict;
+use Test::More;
+use Plack::App::URLMap;
+use Plack::Test;
+use HTTP::Request::Common;
+
+$Plack::Test::Impl = "Server";
+
+my $make_app = sub {
+    my $name = shift;
+    sub {
+        my $env = shift;
+        my $body = join "|", $name, $env->{SCRIPT_NAME}, $env->{PATH_INFO};
+        return [ 200, [ 'Content-Type' => 'text/plain' ], [ $body ] ];
+    };
+};
+
+my $app1 = $make_app->("app1");
+my $app2 = $make_app->("app2");
+
+my $app = Plack::App::URLMap->new;
+$app->map("http://127.0.0.1/" => $app1);
+$app->map("/" => $app2);
+
+test_psgi app => $app, client => sub {
+    my $cb = shift;
+
+    my $res;
+    $res = $cb->(GET "http://127.0.0.1/");
+    is $res->content, 'app1||/';
+};
+
+done_testing;
@@ -5,7 +5,7 @@ use Plack::Request;
 use Plack::Test;
 use HTTP::Request::Common;
 
-my $file = "share/kyoto.jpg";
+my $file = "share/baybridge.jpg";
 
 my @backends = qw( Server MockHTTP );
 sub flip_backend { $Plack::Test::Impl = shift @backends }
@@ -14,7 +14,7 @@ my $app = sub {
     my $req = Plack::Request->new(shift);
     is $req->uploads->{image}->size, -s $file;
     is $req->uploads->{image}->content_type, 'image/jpeg';
-    is $req->uploads->{image}->basename, 'kyoto.jpg';
+    is $req->uploads->{image}->basename, 'baybridge.jpg';
     $req->new_response(200)->finalize;
 };
 
@@ -18,6 +18,8 @@ is_deeply p('-l', ':80'),
     { host => undef, port => 80, listen => [ ':80' ], socket => undef };
 is_deeply p('-l', '10.0.0.1:80', '-l', 'unix.sock'),
     { host => '10.0.0.1', port => 80, listen => [ '10.0.0.1:80', 'unix.sock' ], socket => 'unix.sock' };
+is_deeply p('-l', ':80', '--disable-foo', '--enable-bar'),
+    { host => undef, port => 80, listen => [ ':80' ], socket => undef, foo => '', bar => 1 };
 
 done_testing;